import type { BaseResponse } from "./responses";
import { ResultEnum } from "@/enums/ResultEnum";

export interface UseFetchReturn<R> {
  data: Ref<R | undefined>;
  loading: Ref<boolean>;
  error: Ref<any>;
  reFetch: () => Promise<void>;
}

export function useQueryFetch<T, R extends BaseResponse>(
  fetchFn: (body: T) => Promise<R>,
  query: T | Ref<T>,
  options?: {
    onSuccess?: (data: R) => void;
    onFail?: (code: string, message?: string) => void;
  }
): UseFetchReturn<R> {
  const data = ref<R>();
  const loading = ref(false);
  const error = ref();

  async function doFetch() {
    const q = unref(query);
    try {
      loading.value = true;
      const res = await fetchFn(q);
      data.value = res;
      if (res.code === ResultEnum.SUCCESS) {
        if (options?.onSuccess) options.onSuccess(data.value);
      } else {
        if (options?.onFail) options.onFail(res.code, res.msg);
      }
    } catch (err) {
      error.value = err;
    } finally {
      loading.value = false;
    }
  }
  if (isRef(query)) {
    // setup reactive re-fetch if input URL is a ref
    watchEffect(doFetch);
  } else {
    // otherwise, just fetch once
    doFetch();
  }
  return { data, loading, error, reFetch: doFetch };
}

// 没有watchEffect()
export function usePureFetch<R extends BaseResponse>(
  fetchFn: () => Promise<R>,
  options?: {
    onSuccess?: (data: R) => void;
    onFail?: (code: string, message?: string) => void;
  }
): UseFetchReturn<R> {
  const data = ref<R>();
  const loading = ref(false);
  const error = ref();

  async function doFetch() {
    try {
      loading.value = true;
      const res = await fetchFn();
      data.value = res;
      if (res.code === ResultEnum.SUCCESS) {
        if (options?.onSuccess) options.onSuccess(data.value);
      } else {
        if (options?.onFail) options.onFail(res.code, res.msg);
      }
    } catch (err) {
      error.value = err;
    } finally {
      loading.value = false;
    }
  }
  doFetch();
  return { data, loading, error, reFetch: doFetch };
}
